﻿package htmlelements {
	import flash.display.Sprite;
	import flash.media.Video;
	import flash.media.SoundTransform;
	import org.mangui.hls.HLS;
	import org.mangui.hls.HLSSettings;
	import org.mangui.hls.event.HLSEvent;
	import org.mangui.hls.constant.HLSPlayStates;
	import org.mangui.hls.utils.Log;

	public class HLSMediaElement extends Sprite implements IMediaElement {

		private var _element:FlashMediaElement;
		private var _playqueued:Boolean = false;
		private var _autoplay:Boolean = true;
		private var _preload:String = "";
		private var _hls:HLS;
		private var _url:String;
		private var _video:Video;
		private var _hlsState:String = HLSPlayStates.IDLE;

		// event values
		private var _position:Number = 0;
		private var _duration:Number = 0;
		private var _framerate:Number;
		private var _isManifestLoaded:Boolean = false;
		private var _isPaused:Boolean = true;
		private var _isEnded:Boolean = false;
		private var _volume:Number = 1;
		private var _isMuted:Boolean = false;

		private var _bytesLoaded:Number = 0;
		private var _bytesTotal:Number = 0;
		private var _bufferedTime:Number = 0;
		private var _bufferEmpty:Boolean = false;
		private var _bufferingChanged:Boolean = false;
		private var _seekOffset:Number = 0;


		private var _videoWidth:Number = -1;
		private var _videoHeight:Number = -1;

		public function HLSMediaElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number) {
			_element = element;
			_autoplay = autoplay;
			_volume = startVolume;
			_preload = preload;
			_video = new Video();
			addChild(_video);
			//HLSSettings.logDebug = true;
			_hls = new HLS();
			_hls.addEventListener(HLSEvent.PLAYBACK_COMPLETE,_completeHandler);
			_hls.addEventListener(HLSEvent.ERROR,_errorHandler);
			_hls.addEventListener(HLSEvent.MANIFEST_LOADED,_manifestHandler);
			_hls.addEventListener(HLSEvent.MEDIA_TIME,_mediaTimeHandler);
			_hls.addEventListener(HLSEvent.PLAYBACK_STATE,_stateHandler);
			_hls.addEventListener(HLSEvent.FRAGMENT_PLAYING,_fragmentHandler);
			_hls.stream.soundTransform = new SoundTransform(_volume);
			_video.attachNetStream(_hls.stream);
		}

		private function _completeHandler(event:HLSEvent):void {
			_isEnded = true;
			_isPaused = true;
			sendEvent(HtmlMediaEvent.PAUSE);
			sendEvent(HtmlMediaEvent.ENDED);
		};

		private function _errorHandler(event:HLSEvent):void {
			_element.logMessage(event.toString());
		};

		private function _fragmentHandler(event:HLSEvent):void {
			sendEvent(HtmlMediaEvent.FRAGMENT_PLAYING);
		};

		private function _manifestHandler(event:HLSEvent):void {
			_duration = event.levels[0].duration;
			_videoWidth = event.levels[0].width;
			_videoHeight = event.levels[0].height;
			_isManifestLoaded = true;
			_hls.stage = _video.stage;
			sendEvent(HtmlMediaEvent.LOADEDMETADATA);
			sendEvent(HtmlMediaEvent.CANPLAY);
			if(_autoplay || _playqueued) {
				_playqueued = false;
				_hls.stream.play();
			}
		};

		private function _mediaTimeHandler(event:HLSEvent):void {
			_position = event.mediatime.position;
			_duration = event.mediatime.duration;
			_bufferedTime = event.mediatime.buffer+event.mediatime.position;
			sendEvent(HtmlMediaEvent.PROGRESS);
			sendEvent(HtmlMediaEvent.TIMEUPDATE);
			var videoWidth:int = _video.videoWidth;
			var videoHeight:int = _video.videoHeight;
			var neverSetted:Boolean = _videoWidth <= 0 || _videoHeight <= 0;
			if (videoWidth && videoHeight && neverSetted) {
				_videoHeight = videoHeight;
				_videoWidth = videoWidth;
				_element.setVideoSize(_videoWidth, _videoHeight);
			}
		};

		private function _stateHandler(event:HLSEvent):void {
			_hlsState = event.state;
			//Log.txt("state:"+ _hlsState);
			switch(event.state) {
				case HLSPlayStates.IDLE:
					break;
				case HLSPlayStates.PAUSED_BUFFERING:
				case HLSPlayStates.PLAYING_BUFFERING:
					_isPaused = true;
					sendEvent(HtmlMediaEvent.BUFFERING);
					break;
				case HLSPlayStates.PLAYING:
					_isPaused = false;
					_isEnded = false;
					_video.visible = true;
					sendEvent(HtmlMediaEvent.LOADEDDATA);
					sendEvent(HtmlMediaEvent.PLAY);
					sendEvent(HtmlMediaEvent.PLAYING);
					break;
				case HLSPlayStates.PAUSED:
					_isPaused = true;
					_isEnded = false;
					sendEvent(HtmlMediaEvent.PAUSE);
					sendEvent(HtmlMediaEvent.CANPLAY);
					break;
			}
		};

		public function get video():Video {
			return _video;
		}

		public function get videoHeight():Number {
			return _videoHeight;
		}

		public function get videoWidth():Number {
			return _videoWidth;
		}

		public function play():void {
			//Log.txt("HLSMediaElement:play");
			if(!_isManifestLoaded) {
				_playqueued = true;
				return;
			}
			if (_hlsState == HLSPlayStates.PAUSED || _hlsState == HLSPlayStates.PAUSED_BUFFERING) {
				_hls.stream.resume();
			} else {
				_hls.stream.play();
			}
		}

		public function pause():void {
			if(!_isManifestLoaded)
				return;
			//Log.txt("HLSMediaElement:pause");
			_hls.stream.pause();
		}

		public function load():void{
			//Log.txt("HLSMediaElement:load");
			if(_url) {
				sendEvent(HtmlMediaEvent.LOADSTART);
				_hls.load(_url);
			}
		}

		public function stop():void{
			_hls.stream.close();
			_video.clear();
			_isManifestLoaded = false;
			_duration = 0;
			_position = 0;
			_playqueued = false;
			sendEvent(HtmlMediaEvent.STOP);
		}

		public function setSrc(url:String):void{
			//Log.txt("HLSMediaElement:setSrc:"+url);
			stop();
			_url = url;
			_hls.load(_url);
		}

		public function setSize(width:Number, height:Number):void{
			_video.width = width;
			_video.height = height;
		}

		public function setCurrentTime(pos:Number):void{
			if(!_isManifestLoaded)
				return;
			sendEvent(HtmlMediaEvent.SEEKING);
			_hls.stream.seek(pos);
		}

		public function setVolume(vol:Number):void{
			_volume = vol;
			_isMuted = (_volume == 0);
			_hls.stream.soundTransform = new SoundTransform(vol);
			sendEvent(HtmlMediaEvent.VOLUMECHANGE);
		}

		public function getVolume():Number {
			if(_isMuted) {
				return 0;
			} else {
				return _volume;
			}
		}

		public function setMuted(muted:Boolean):void {
			// ignore if no change
			if (muted === _isMuted)
				return;

			_isMuted = muted;

			if (muted) {
				_hls.stream.soundTransform = new SoundTransform(0);
				sendEvent(HtmlMediaEvent.VOLUMECHANGE);
			} else {
				setVolume(_volume);
			}
		}

		public function duration():Number{
			return _duration;
		}

		public function currentTime():Number{
			return _position;
		}

		public function seekLimit():Number {
			return _duration;
		}

		public function currentProgress():Number {
			var progress:Number = 0;
			if (_duration != 0) {
				progress = Math.round( (_bufferedTime / _duration) * 100 );
			}
			return progress;
		}

		private function sendEvent(eventName:String):void {
			// build JSON
			var values:String =
				"duration:" + _duration +
				",framerate:" + _hls.stream.currentFPS +
				",currentTime:" + _position +
				",muted:" + _isMuted +
				",paused:" + _isPaused +
				",ended:" + _isEnded +
				",volume:" + _volume +
				",src:\"" + _url + "\"" +
				",bytesTotal:" + Math.round(1000*_duration) +
				",bufferedBytes:" + Math.round(1000*(_position+_bufferedTime)) +
				",bufferedTime:" + _bufferedTime +
				",videoWidth:" + _videoWidth +
				",videoHeight:" + _videoHeight +
				"";
			_element.sendEvent(eventName, values);
		}

	}
}